#include "usr_include.h"

#define USART_MSG_NUM 3
#define USART_BUFFER_SIZE 200
#define USART_HANDLE huart1
#define USART_DMA_RX_HANDLE hdma_usart1_rx
#define USART_DMA_TX_HANDLE hdma_usart1_tx

static osSemaphoreId_t sid_Semaphore;
static osMessageQueueId_t myQueueRxHandle;
static uint8_t usart_rx_table[USART_MSG_NUM][USART_BUFFER_SIZE];
static uint16_t connect_flag_count = 0;

static void usart_init(void);
static void usart_isr(void);
static void usart_task(void);
static int32_t usart_log(int8_t level, int8_t *fmt, ...);

struct app_usb_struct_def app_usb_struct = {
    .init = usart_init,
    .isr = usart_isr,
    .task = usart_task,
    .log = usart_log,
};

static void usart_init(void)
{
    __HAL_UART_ENABLE_IT(&USART_HANDLE, UART_IT_IDLE);
    myQueueRxHandle = osMessageQueueNew(USART_MSG_NUM, 4, NULL);
    HAL_UART_Receive_DMA(&USART_HANDLE, usart_rx_table[0], USART_BUFFER_SIZE);
}
/****************************************************************************
 * name:usart_read
 * function: block read function
 * in parameters : buffer:store table  count:buffer size
 * out parameters : no
 ****************************************************************************/
static uint8_t usart_read(uint8_t *buffer, uint8_t *count, uint32_t wait_count)
{
    uint32_t value;
    osStatus_t temp;
    uint8_t *p;
    uint8_t ret;

    temp = osMessageQueueGet(myQueueRxHandle, &value, NULL, wait_count);
    if (temp == osOK)
    {
        taskENTER_CRITICAL();
        p = (uint8_t *)value;
        *count = p[USART_BUFFER_SIZE - 1];
        if (*count > USART_BUFFER_SIZE - 1)
        {
            *count = USART_BUFFER_SIZE - 1;
        }
        memcpy(buffer, p, *count);
        taskEXIT_CRITICAL();
        ret = 0;
    }
    else
    {
        ret = 1;
    }
    return ret;
}

/****************************************************************************
 * name:usart_write
 * function: block usart write
 * in parameters : buffer : send table count send size
 * out parameters : no
 ****************************************************************************/
static void usart_write(uint8_t *buffer, uint8_t count)
{
    if (count > USART_BUFFER_SIZE)
    {
        count = USART_BUFFER_SIZE;
    }
    // SCB_CleanInvalidateDCache();
    HAL_UART_Transmit_DMA(&USART_HANDLE, buffer, count);
    do
    {
        osDelay(1);
    } while (HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY);
}
/****************************************************************************
 * name:usart_isr
 * function: usart isr function
 * in parameters : no
 * out parameters : no
 ****************************************************************************/
static void usart_isr(void)
{
    static uint8_t count = 0;
    uint32_t p = 0;
    uint8_t dma_count = 0;
    uint8_t temp = 0;

    if (__HAL_UART_GET_FLAG(&USART_HANDLE, UART_FLAG_IDLE))
    {
        __HAL_UART_CLEAR_IDLEFLAG(&USART_HANDLE);
        dma_count = __HAL_DMA_GET_COUNTER(&USART_DMA_RX_HANDLE);
        temp = USART_BUFFER_SIZE - dma_count;
        dma_count = temp;
        if (osMessageQueueGetCount(myQueueRxHandle) == USART_MSG_NUM)
        {
            osMessageQueueGet(myQueueRxHandle, &p, NULL, 0); // clear old data
        }
        HAL_UART_AbortReceive(&USART_HANDLE);
        // SCB_CleanInvalidateDCache();
        p = (uint32_t)usart_rx_table[count];
        usart_rx_table[count][USART_BUFFER_SIZE - 2] = 0;
        usart_rx_table[count][USART_BUFFER_SIZE - 1] = dma_count;
        osMessageQueuePut(myQueueRxHandle, &p, NULL, 0);
        count++;
        if (count >= USART_MSG_NUM)
        {
            count = 0;
        }
        HAL_UART_Receive_DMA(&USART_HANDLE, usart_rx_table[count], USART_BUFFER_SIZE);
    }
}

/****************************************************************************
 * name:usart_clear_buffer
 * function: clear all message in msgqueue
 * in parameters : no
 * out parameters : no
 ****************************************************************************/
static void usart_clear_buffer(void)
{
    osMessageQueueReset(myQueueRxHandle);
}
/****************************************************************************
 * name:usart_task
 * function:
 * in parameters :
 * out parameters : no
 ****************************************************************************/
static void usart_task(void)
{
    static uint8_t buffer[USART_BUFFER_SIZE];
    uint8_t read_count;
    uint8_t temp0;
    uint16_t devive_id;

    int32_t crc = 0;
    int32_t recv_crc = 0;

    while (1)
    {
        osDelay(1);
        memset(buffer, 0, USART_BUFFER_SIZE);
        temp0 = usart_read(buffer, &read_count, 0);
        if (temp0 != 0)
            continue;
        usart_write(buffer, read_count);
        recv_crc++;
    }
}

static int32_t usart_log(int8_t level, int8_t *fmt, ...)
{

    static unsigned char buffer[USART_BUFFER_SIZE];
    va_list argptr;
    int cnt;

    if (level <= LOG_LEVEL)
    {
        buffer[0] = 0;
        switch (level)
        {
        case (LOG_DEBUG):
            strcat(buffer, "debug:");
            break;
        case (LOG_WARN):
            strcat(buffer, "warn :");
            break;
        case (LOG_ERROR):
            strcat(buffer, "error:");
            break;
        default:
            strcat(buffer, "debug:");
        }
        va_start(argptr, fmt);
        vsnprintf(&buffer[6], 250, fmt, argptr);
        usart_write(buffer, strlen(buffer));
        va_end(argptr);
    }
    return 0;
}
